﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DatabaseSimulation
{
    public class DatabaseOperationGenerator
    {
        private Random Random { get; set; }
        private GaussianRandom GaussianRandom { get; set; }
        public double WritePercentage { get; private set; }
        public double ReadPercentage { get; private set; }
        public int CpuTimeMean { get; private set; }
        public int CpuTimeStdDev { get; private set; }
        public int IoTimeMean { get; private set; }
        public int IoTimeStdDev { get; private set; }

        public DatabaseOperationGenerator(Random random, GaussianRandom gaussianRandom, double writePercentage, int cpuTimeMean, int cpuTimeStdDev, int ioTimeMean, int ioTimeStdDev)
        {
            if (writePercentage < 0 || writePercentage > 1)
            {
                throw new Exception("WritePercentage must be between 0 and 1");
            }

            this.Random = random;
            this.GaussianRandom = gaussianRandom;
            this.WritePercentage = writePercentage;
            this.ReadPercentage = 1 - writePercentage;
            this.CpuTimeMean = cpuTimeMean;
            this.CpuTimeStdDev = cpuTimeStdDev;
            this.IoTimeMean = ioTimeMean;
            this.IoTimeStdDev = ioTimeStdDev;
        }

        private int GetRandomObjectID(int numberOfObjects)
        {
            return this.Random.Next(numberOfObjects);
        }

        private int GetRandomCpuTime()
        {
            return Math.Max(1, GaussianRandom.NextGaussianInt(CpuTimeMean, CpuTimeStdDev));
        }

        private int GetRandomIoTime()
        {
            return Math.Max(1, GaussianRandom.NextGaussianInt(IoTimeMean, IoTimeStdDev));
        }

        private DatabaseOperationType GetRandomOperationType()
        {
            return this.Random.NextDouble() < this.ReadPercentage ? DatabaseOperationType.Read : DatabaseOperationType.Write;
        }

        public DatabaseOperation GenerateDatabaseOperation(Transaction transaction, int numberOfObjects)
        {
            return new DatabaseOperation(transaction, GetRandomOperationType(), GetRandomObjectID(numberOfObjects), GetRandomIoTime(), GetRandomCpuTime());
        }
    }
}
